home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1999 July: Mac OS SDK / Dev.CD Jul 99 SDK1.toast / Development Kits / Mac OS / QuickDraw3D 1.6 SDK / Mac SampleCode Previous / Viewer Samples - Mac / SimpleViewer / SimpleViewer.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-05-18  |  26.5 KB  |  1,094 lines  |  [TEXT/MPCC]

  1. //--------------------------------------------------------------------------------------------
  2. // simple viewer application 
  3. // DEVELOPER SUPPORT May 95
  4. //
  5. // This is a simple viewer application, that illustrates a minimal, but
  6. // functionally complete viewer application.
  7. //
  8. // Nick Thompson, Developer Support, Apple Computer (DEVSUPPORT),
  9. // ©1995, Apple Computer Inc., All Rights Reserved
  10.  
  11. #include <AppleEvents.h>
  12. #include <menus.h>
  13. #include <PictUtils.h>
  14. #include <QDOffScreen.h>
  15. #include <Errors.h>
  16.  
  17. #include "QD3D.h"
  18. #include "QD3DViewer.h"
  19. #include "QD3DGestalt.h"
  20. #include "QD3DViewerGestalt.h"
  21.  
  22. //--------------------------------------------------------------------------------------------
  23. //
  24. const int    kWindowWidth = 220 ;
  25. const int    kWindowHeight = 150 ;
  26.  
  27. //--------------------------------------------------------------------------------------------
  28. //
  29. #define HiWrd(aLong)    (((aLong) >> 16) & 0xFFFF)
  30. #define LoWrd(aLong)    ((aLong) & 0xFFFF)
  31.  
  32.     
  33.  
  34. //--------------------------------------------------------------------------------------------
  35. // menu id's
  36. enum {
  37.     mApple = 128,
  38.     mFile,
  39.     mEdit
  40. } ;
  41.  
  42. //--------------------------------------------------------------------------------------------
  43. // command id's, Apple menu
  44. enum {
  45.     iAbout = 1
  46. } ;
  47.  
  48. //--------------------------------------------------------------------------------------------
  49. // command id's, File menu
  50. enum {
  51.     iNew = 1,
  52.     iOpen,
  53.     iUnused1,
  54.     iClose,
  55.     iSave,
  56.     iSaveAs,
  57.     iRevert,
  58.     iUnused2,
  59.     iQuit
  60. } ;
  61.  
  62. //--------------------------------------------------------------------------------------------
  63. // command id's, Edit menu
  64. enum {
  65.     iUndo = 1,
  66.     iUnused3,
  67.     iCut,
  68.     iCopy,
  69.     iPaste,
  70.     iClear
  71. } ;
  72.  
  73. //--------------------------------------------------------------------------------------------
  74. // static control variables
  75.  
  76. static Boolean gQuitFlag = false ;                // we ain't quittin yet
  77. static Point gStaggerPos = {50,50} ;            // start opening staggered windows at this point
  78. static AEAddressDesc    gSelfAddress;            // A self-addressed address descriptor record
  79. static ProcessSerialNumber    gSelfPSN;            // This application's psn
  80.  
  81. //--------------------------------------------------------------------------------------------
  82. // function prototypes
  83.  
  84. Boolean SupportsQuickDraw3D(void) ;
  85. Boolean     SupportsQuickDraw3DViewer(void) ;
  86. void         InitToolbox( void ) ;
  87. void        FailIfErr(OSErr something ) ;
  88. void         MainEventLoop( void ) ;
  89. void         HandleKeyPress( EventRecord *event ) ;
  90. Boolean        HandleEvent( EventRecord *theEvent ) ;
  91. void         HandleMenuCommand( long menuResult ) ;
  92. void         MyAdjustMenus( void ) ;
  93. OSErr        MyDisposeViewerWindow( WindowPtr theWindow ) ;
  94. CGrafPtr     MyCreateViewerWindow( void ) ;
  95.  
  96. //-- AppleEvent Related
  97.  
  98. Boolean SupportsAEVT(void) ;
  99. void RegisterMyEvents(void) ;
  100. pascal OSErr MyAEHandleOAPP( AppleEvent *theAppleEvent, AppleEvent *reply, long refCon) ;
  101. pascal OSErr MyAEHandleODOC(AppleEvent *theAppleEvent, AppleEvent *reply, long refCon) ;
  102. pascal OSErr MyAEHandlePDOC(AppleEvent *theAppleEvent,AppleEvent *reply,long refCon) ;
  103. pascal OSErr MyAEHandleQUIT(AppleEvent *theAppleEvent,AppleEvent *reply,long refCon) ;
  104. void DoAppOpenCommand( void ) ;
  105. void MySendQuitApp( void ) ;
  106. void MySendOpenDoc(FSSpec *myFSSpec) ;
  107.  
  108. //--------------------------------------------------------------------------------------------
  109. // Constants
  110.  
  111. const RGBColor    kRGBBlack = { 0x0000, 0x0000, 0x0000 } ;
  112. const RGBColor    kRGBWhite = { 0xFFFF, 0xFFFF, 0xFFFF } ;
  113. const int         kMyAboutDialogID = 128 ;
  114. const int         kMyFatalDialogID = 129 ;
  115. const int        kQD3DAlertID = 27309 ;
  116. //--------------------------------------------------------------------------------------------
  117. // Types
  118. typedef struct _viewerData {
  119.     TQ3ViewerObject        theViewer ;
  120.     FSSpec                theFile ;
  121.     Boolean                isFileValid ;
  122. } ViewerData, *ViewerDataPtr, **ViewerDataHandle ;
  123.  
  124. //--------------------------------------------------------------------------------------------
  125. //
  126. //
  127.  
  128. main()
  129. {
  130.     MoreMasters(); MoreMasters() ; MoreMasters() ;
  131.     MaxApplZone() ;            // Maximise the heap - the viewer requires at least 32k
  132.     InitToolbox() ;
  133.  
  134.     // WE DON'T CHECK FOR 68K machine.
  135.     // Instead I use the NotPPC.rsrc resource file.  This is a file with a 68k CODE 0
  136.     // and CODE 1 resource that puts up a dialog that says "this app only runs on a power
  137.     // macintosh computer.
  138.     
  139.     if( SupportsAEVT() && SupportsQuickDraw3D() && SupportsQuickDraw3DViewer()  ) {
  140.     
  141.         // AppleEvent stuff:
  142.         // Set up the self-addressed descriptor record.
  143.          gSelfPSN.highLongOfPSN = 0;
  144.          gSelfPSN.lowLongOfPSN = kCurrentProcess;        //* Use this instead of GetCurrentProcess *//
  145.          FailIfErr(AECreateDesc(typeProcessSerialNumber,(Ptr)&gSelfPSN,sizeof(ProcessSerialNumber),&gSelfAddress));
  146.  
  147.         RegisterMyEvents() ;    // register the appleevents for this app
  148.  
  149.         MainEventLoop() ;        // Handle events 'til we die
  150.     } 
  151.     else {
  152.         Str255 theString ;
  153.         GetIndString(theString,kQD3DAlertID,3);
  154.         ParamText( theString, 0L,  0L,  0L ) ;
  155.         (void)Alert(kQD3DAlertID,nil);
  156.     }
  157. }
  158. //---------------------------------------------------------------------
  159.  
  160. Boolean SupportsQuickDraw3D(void) 
  161. {
  162.     OSErr err;
  163.     long response;
  164.         
  165.     err = Gestalt(gestaltQD3D,&response);
  166.     if (err!=noErr)
  167.         return false;
  168.         
  169.     return (response && (response << gestaltQD3DAvailable));
  170. }
  171.  
  172. //---------------------------------------------------------------------
  173.  
  174. Boolean SupportsQuickDraw3DViewer(void) 
  175. {
  176.     OSErr err;
  177.     long response;
  178.         
  179.     err = Gestalt( gestaltQD3DViewer,&response );
  180.     if (err!=noErr)
  181.         return false;
  182.         
  183.     return (response && ( response << gestaltQD3DViewerAvailable ));
  184. }
  185.  
  186. //--------------------------------------------------------------------------------------------
  187. //
  188. //
  189. void FailIfErr( OSErr something )
  190.     OSErr myErr ; 
  191.     if(( myErr = something) != noErr ) { 
  192.         ModalFilterUPP         theProc ;
  193.         DialogPtr            theDialog ; 
  194.         short                itemHit ;
  195.         Str255                theError ;
  196.         
  197.         NumToString(something,theError);
  198.     
  199.         theDialog = GetNewDialog ( kMyFatalDialogID, nil, (WindowPtr)-1 );
  200.         
  201.         // these two lil' snappers are system 7 only
  202.         // so if you use them, check before!!
  203.         // in this app we will only run on Power
  204.         // Macintosh, so we don't check
  205.         
  206.         GetStdFilterProc( &theProc ) ;
  207.         SetDialogDefaultItem(theDialog, ok) ;
  208.         
  209.         ParamText( theError, 0L, 0L, 0L ) ;
  210.         
  211.         // put the dialog up and loop 'til
  212.         // the user hits the OK button
  213.  
  214.         do {
  215.             ModalDialog ( theProc, &itemHit );
  216.         } while( itemHit != ok ) ;
  217.         
  218.         DisposeDialog ( theDialog );
  219.         
  220.         ExitToShell() ; 
  221.     } 
  222.  
  223. //--------------------------------------------------------------------------------------------
  224. //
  225. //
  226.  
  227. void InitToolbox()
  228. {
  229.     Handle        menuBar = nil;
  230.  
  231.  
  232.     InitGraf((Ptr) &qd.thePort);
  233.     InitFonts();
  234.     InitWindows();
  235.     InitMenus();
  236.     TEInit();
  237.     InitDialogs((long)nil);
  238.     InitCursor();
  239.  
  240.     // initialize application globals
  241.     
  242.     gQuitFlag = false;
  243.     
  244.     
  245.     menuBar = GetNewMBar(128);                // Read menus into menu bar, MBAR res id is 128
  246.     
  247.     if ( menuBar == nil )
  248.          ExitToShell();                        // if we dont have it then quit - your app 
  249.                                              // needs a dialog here
  250.  
  251.     SetMenuBar(menuBar);                    // Install menus
  252.     DisposeHandle(menuBar);
  253.     
  254.     AppendResMenu(GetMenuHandle(mApple), 'DRVR');    // Add DA names to Apple menu, ID 128
  255.  
  256.     MyAdjustMenus() ;
  257.     DrawMenuBar();
  258. }
  259.  
  260.  
  261. //--------------------------------------------------------------------------------------------
  262. //
  263. //
  264. void MainEventLoop()
  265. {
  266.     EventRecord         event;
  267.     WindowPtr           theWindow;
  268.     Boolean                wasViewerEvent ;
  269.     GrafPtr             savedPort ;
  270.     Point                localPt ;
  271.     TQ3ViewerObject     theViewer ;
  272.     ViewerDataHandle    myData ;
  273.  
  274.     MyAdjustMenus() ;
  275.     while( !gQuitFlag )
  276.     {
  277.         if (WaitNextEvent( everyEvent, &event, 0, nil ))
  278.         {
  279.             
  280.             if((theWindow = FrontWindow()) != nil ) {
  281.             
  282.                 myData = (ViewerDataHandle)GetWRefCon(theWindow);
  283.                 theViewer = (**myData).theViewer;
  284.             }
  285.             
  286.             if( theViewer ) {
  287.                 GetPort( &savedPort ) ;
  288.                 SetPort( (GrafPtr)theWindow ) ;
  289.                 GetMouse(&localPt);
  290.                 if (!Q3ViewerAdjustCursor(theViewer, &localPt))
  291.                     InitCursor();
  292.                 wasViewerEvent = Q3ViewerEvent ( theViewer, &event );
  293.                 SetPort( savedPort ) ;
  294.             }
  295.             else
  296.                 wasViewerEvent = false ;
  297.             
  298.             // was it a viewer event????
  299.             if( !wasViewerEvent )
  300.                 HandleEvent( &event );
  301.         }
  302.     }
  303. }
  304.  
  305. //----------------------------------------------------------------------------------
  306. //    HandleActivateWindow is called when an event is received that reports that
  307. //    a window is being either activated or deactivated.
  308.  
  309. static void HandleActivateWindow(WindowPtr theWindow, short activate)
  310. {
  311.     if (theWindow) {
  312.         if (activate) {
  313.         
  314.             // do whatever else you'd like to do for a activate event
  315.             LoadScrap() ;
  316.  
  317.         } else {
  318.         
  319.             // do whatever you'd like to do for a deactivate event
  320.             UnloadScrap() ;
  321.         }
  322.     }
  323. }
  324.  
  325. //--------------------------------------------------------------------------------------------
  326. //
  327. //
  328. Boolean        HandleEvent( EventRecord *theEvent )
  329. {
  330.     short               thePart;
  331.     WindowPtr            theWindow ;
  332.     Rect                screenRect;
  333.     GrafPtr                oldPort ;
  334.     Point                aPoint = {100, 100};
  335.     TQ3ViewerObject     theViewer ;
  336.     ViewerDataHandle    myData ;
  337.     
  338.     switch (theEvent->what) {
  339.         case mouseDown:
  340.         
  341.             thePart = FindWindow( theEvent->where, &theWindow );
  342.             
  343.             switch( thePart ) {
  344.                 case inMenuBar: 
  345.                     MyAdjustMenus() ;
  346.                     HandleMenuCommand(MenuSelect(theEvent->where));
  347.                     break;
  348.                 
  349.                 case inDrag:
  350.                     screenRect = (**GetGrayRgn()).rgnBBox;
  351.                     DragWindow( theWindow, theEvent->where, &screenRect );
  352.                     break ;
  353.             
  354.                 case inContent:
  355.                     if (theWindow != FrontWindow())
  356.                         SelectWindow( theWindow );
  357.                     break ;
  358.             
  359.                 case inGoAway:
  360.                     if (TrackGoAway( theWindow, theEvent->where )) {
  361.                         MyDisposeViewerWindow( theWindow ) ;
  362.                     }
  363.                     break ;
  364.                     
  365.                 default:
  366.                     break ;
  367.             }
  368.             break ;
  369.                     
  370.                 
  371.         case updateEvt:
  372.         
  373.             theWindow = (WindowPtr)theEvent->message;
  374.             myData = (ViewerDataHandle)GetWRefCon( theWindow ) ;
  375.             theViewer = (**myData).theViewer ;
  376.             
  377.             GetPort(&oldPort ) ;    
  378.             SetPort( theWindow );
  379.             
  380.             BeginUpdate( theWindow );
  381.             Q3ViewerDraw( theViewer ) ;
  382.             EndUpdate( theWindow );
  383.             
  384.             SetPort( oldPort ) ;
  385.             
  386.             break ;
  387.             
  388.         case keyDown:
  389.         case autoKey:
  390.             HandleKeyPress(theEvent);
  391.             break;
  392.             
  393.         case diskEvt:
  394.             if ( HiWrd(theEvent->message) != noErr ) 
  395.                 (void) DIBadMount(aPoint, theEvent->message);
  396.             break;
  397.             
  398.         case osEvt:
  399.             break ;
  400.         case activateEvt:
  401.             if ((theWindow = (WindowPtr) theEvent->message) != nil) {
  402.                 HandleActivateWindow(theWindow, (theEvent->modifiers & activeFlag));
  403.             }
  404.  
  405.             break;
  406.  
  407.         case kHighLevelEvent:                        // Let the Apple Event Manager handle high level event.
  408.             AEProcessAppleEvent(theEvent);
  409.             break;
  410.  
  411.     }
  412.     return true ;
  413. }
  414.  
  415.  
  416. //--------------------------------------------------------------------------------------------
  417. //
  418. //
  419. void HandleKeyPress(EventRecord *event)
  420. {
  421.     char    key;
  422.  
  423.     key = event->message & charCodeMask;
  424.     
  425.     // just check to see if we want to quit...
  426.     
  427.     if ( event->modifiers & cmdKey ) {        /* Command key down? */
  428.         HandleMenuCommand(MenuKey(key));
  429.     } 
  430. }
  431.  
  432. //--------------------------------------------------------------------------------------------
  433. //
  434. //
  435.  
  436. static void HandleAboutApp( void )
  437. {
  438.     ModalFilterUPP         theProc ;
  439.     DialogPtr            theDialog ; 
  440.     short                itemHit ;
  441.  
  442.     theDialog = GetNewDialog ( kMyAboutDialogID, nil, (WindowPtr)-1 );
  443.     
  444.     // these two lil' snappers are system 7 only
  445.     // so if you use them, check before!!
  446.     // in this app we will only run on Power
  447.     // Macintosh, so we don't check
  448.     
  449.     GetStdFilterProc( &theProc ) ;
  450.     SetDialogDefaultItem(theDialog, ok) ;
  451.     
  452.     // put the dialog up and loop 'til
  453.     // the user hits the OK button
  454.     
  455.     do {
  456.         ModalDialog ( theProc, &itemHit );
  457.     } while( itemHit != ok ) ;
  458.     
  459.     DisposeDialog ( theDialog );
  460. }
  461.  
  462. //--------------------------------------------------------------------------------------------
  463. //
  464. //
  465. static OSErr HandleOpenDoc(FSSpec *theFile)
  466. {
  467.     OSErr                err ;
  468.     short                theRef ;
  469.     ViewerDataHandle    myData ;
  470.     TQ3ViewerObject     theViewer ;
  471.     WindowPtr            theWindow ;
  472.  
  473.     // display the contents
  474.     theWindow = (WindowPtr)MyCreateViewerWindow() ;
  475.     
  476.     // open the file
  477.     err = FSpOpenDF( theFile, fsRdPerm, &theRef ) ;
  478.     if (err == noErr)
  479.     {
  480.         myData = (ViewerDataHandle)GetWRefCon( theWindow ) ;
  481.         theViewer = (**myData).theViewer ;
  482.         (**myData).theFile = *theFile ;
  483.         (**myData).isFileValid = true ;
  484.         Q3ViewerUseFile(theViewer, theRef) ;
  485.         err = FSClose(theRef) ;
  486.     }
  487.     
  488.     // set the window title
  489.     SetWTitle( theWindow, theFile->name );
  490.     MyAdjustMenus() ;
  491.     return err ;
  492. }
  493.  
  494.  
  495. //--------------------------------------------------------------------------------------------
  496. //
  497. //
  498. void HandleMenuCommand(long menuResult)
  499. {
  500.     short                menuID;
  501.     short                menuItem;
  502.     Str255                daName;
  503.     
  504.  
  505.     short                numTypes = 2 ;
  506.     SFTypeList            myTypes = { '3DMF', 'TEXT', 0 } ;
  507.     OSErr                err ;
  508.     short                theRef ;
  509.     
  510.     ViewerDataHandle    myData ;
  511.     TQ3ViewerObject     theViewer ;
  512.     WindowPtr            theWindow ;
  513.     GrafPtr                savedPort ;
  514.     
  515.     FSSpec                theFile ;
  516.         
  517.     StandardFileReply    theSFReply ;
  518.  
  519.     menuID = HiWrd(menuResult);
  520.     menuItem = LoWrd(menuResult);
  521.     
  522.     switch ( menuID ) {
  523.         //
  524.         //--------------------------------------------------------------------------    
  525.         //
  526.         case mApple:
  527.             switch ( menuItem ) {
  528.  
  529.                 case iAbout:
  530.                     HandleAboutApp() ;    
  531.                     break ;
  532.                                 
  533.                 default:
  534.                     GetMenuItemText(GetMenuHandle(mApple), menuItem, daName);
  535.                     (void) OpenDeskAcc(daName);
  536.                     break;
  537.             }
  538.             break;
  539.         //
  540.         //--------------------------------------------------------------------------    
  541.         //
  542.         case mFile:
  543.             switch ( menuItem ) {
  544.                 case iNew:
  545.                     // display the contents
  546.                     (void)MyCreateViewerWindow() ;
  547.                     break ;
  548.                 
  549.                 case iOpen:
  550.                     // Get the file name to open
  551.                     StandardGetFile( nil, numTypes, myTypes, &theSFReply ) ;
  552.                     
  553.                     // did the user cancel, if not open the file?
  554.                     if(theSFReply.sfGood)
  555.                         MySendOpenDoc(&theSFReply.sfFile) ;
  556.  
  557.                     break ;
  558.                     
  559.                     
  560.                 case iRevert:
  561.                 
  562.                     // we know this can't be called as long as there
  563.                     // is an app window open (MyAdjustMenus) so get the refcon
  564.                     // from the front window and get the FSSpec from that
  565.                     theWindow = FrontWindow() ;
  566.                     myData = (ViewerDataHandle)GetWRefCon( theWindow ) ;
  567.                     theFile = (**myData).theFile ;
  568.                     
  569.                     // open the file and read it back into the viewer
  570.                     err = FSpOpenDF( &theFile, fsRdPerm, &theRef ) ;
  571.                     if (err == noErr)
  572.                     {
  573.                         theViewer = (**myData).theViewer ;
  574.                         Q3ViewerUseFile(theViewer, theRef) ;
  575.                         err = FSClose(theRef) ;
  576.                     }
  577.                     GetPort( &savedPort ) ;
  578.                     SetPort((GrafPtr)theWindow) ;
  579.                     InvalRect( &theWindow->portRect ) ;
  580.                     SetPort( savedPort ) ;
  581.                     break ;        
  582.                             
  583.                 case iSave:                
  584.                 
  585.                     // we know this can't be called as long as there
  586.                     // is an app window open (MyAdjustMenus) so get the refcon
  587.                     // from the front window and get the FSSpec from that
  588.                     theWindow = FrontWindow() ;
  589.                     myData = (ViewerDataHandle)GetWRefCon( theWindow ) ;
  590.                     theFile = (**myData).theFile ;
  591.                     theViewer = (**myData).theViewer ;
  592.  
  593.                     // assumes the original file still exists
  594.                     err = FSpOpenDF(&theFile, fsWrPerm, &theRef);
  595.                     if (err == noErr)
  596.                     {
  597.                         Q3ViewerWriteFile(theViewer, theRef);
  598.                         err = FSClose(theRef);
  599.                     }
  600.                     break ;
  601.                 
  602.                 case iSaveAs:
  603.                     // we know this can't be called as long as there
  604.                     // is an app window open (MyAdjustMenus) so get the refcon
  605.                     // from the front window and get the FSSpec from that
  606.                     theWindow = FrontWindow() ;
  607.                     myData = (ViewerDataHandle)GetWRefCon( theWindow ) ;
  608.                     theViewer = (**myData).theViewer ;
  609.  
  610.                     StandardPutFile("\pSave model as:", "\pUntitled", &theSFReply);
  611.                     if (theSFReply.sfGood)
  612.                     {
  613.                         err = FSpOpenDF(&theSFReply.sfFile, fsWrPerm, &theRef);
  614.                         if (err != noErr)
  615.                         {
  616.                             err = FSpCreate(&theSFReply.sfFile, '????', '3DMF', theSFReply.sfScript);
  617.                             if (err == noErr)
  618.                                 err = FSpOpenDF(&theSFReply.sfFile, fsCurPerm, &theRef);
  619.                         }
  620.                         if (err == noErr)
  621.                         {
  622.                             Q3ViewerWriteFile(theViewer, theRef);
  623.                             err = FSClose(theRef);
  624.                         }
  625.                         
  626.                         // set up our record of the file location,
  627.                         // update the structure
  628.                         theWindow = FrontWindow() ;
  629.                         myData = (ViewerDataHandle)GetWRefCon( theWindow ) ;
  630.                         theViewer = (**myData).theViewer ;
  631.                         (**myData).theFile = theSFReply.sfFile ;
  632.                         (**myData).isFileValid = true ;
  633.                         
  634.                         // reset the window title
  635.                         SetWTitle( theWindow, theSFReply.sfFile.name );
  636.                     }
  637.                     break;                
  638.                 
  639.                 case iClose:
  640.                     MyDisposeViewerWindow ( FrontWindow() );
  641.                     break ;
  642.                     
  643.                 case iQuit:
  644.                     MySendQuitApp();
  645.                     break;
  646.             }
  647.             break;
  648.             
  649.             
  650.         //
  651.         //--------------------------------------------------------------------------    
  652.         //
  653.         case mEdit:
  654.             // display the contents
  655.             theWindow = FrontWindow() ;
  656.             myData = (ViewerDataHandle)GetWRefCon( theWindow ) ;
  657.             theViewer = (**myData).theViewer ;
  658.             switch(menuItem)
  659.             {
  660.                 case iCut:
  661.                     Q3ViewerCut(theViewer);
  662.                     break;
  663.                 case iCopy:
  664.                     Q3ViewerCopy(theViewer);
  665.                     break;
  666.                 case iPaste:
  667.                     Q3ViewerPaste(theViewer);
  668.                     break;
  669.                 case iClear:
  670.                     Q3ViewerClear(theViewer);
  671.                     break;
  672.                 default:
  673.                     break;
  674.             }
  675.             break; 
  676.  
  677.     }
  678.     HiliteMenu(0);        // Unhighlight whatever MenuSelect or MenuKey hilited
  679. }
  680.  
  681. //--------------------------------------------------------------------------------------------
  682. //
  683. //
  684. void MyAdjustMenus( void ) 
  685. {
  686.     WindowPtr            theWindow ;
  687.     ViewerDataHandle    myData ;
  688.     MenuHandle            theMenu ;
  689.  
  690.     theWindow = FrontWindow() ;
  691.     
  692.     
  693.     if( theWindow != nil ) {
  694.     
  695.         theMenu =  GetMenuHandle ( mFile ) ;
  696.         
  697.         EnableItem ( theMenu, iClose );
  698.         EnableItem ( theMenu, iSaveAs );
  699.                  
  700.         myData = (ViewerDataHandle)GetWRefCon( theWindow ) ;
  701.         
  702.          if(    (**myData).isFileValid) {
  703.             EnableItem ( theMenu, iSave );
  704.             EnableItem (theMenu, iRevert );
  705.          }
  706.          else {
  707.             DisableItem ( theMenu, iSave );
  708.             DisableItem ( theMenu, iRevert );
  709.          
  710.          }
  711.          
  712.          EnableItem ( GetMenuHandle ( mEdit ), 0 );
  713.  
  714.     }
  715.     else {
  716.  
  717.         theMenu =  GetMenuHandle ( mFile ) ;
  718.  
  719.         DisableItem ( theMenu, iClose );
  720.         DisableItem ( theMenu, iRevert );
  721.         DisableItem ( theMenu, iSave );
  722.         DisableItem ( theMenu, iSaveAs );
  723.         
  724.         DisableItem ( GetMenuHandle ( mEdit ), 0 );
  725.     }
  726.     
  727.     // we don't support undo
  728.     DisableItem ( GetMenuHandle ( mEdit ), iUndo );
  729.     
  730.     DrawMenuBar() ;
  731. }
  732.  
  733.  
  734. //--------------------------------------------------------------------------------------------
  735. //
  736. //
  737. OSErr    MyDisposeViewerWindow( WindowPtr theWindow )
  738. {
  739.     TQ3ViewerObject     theViewer ;
  740.     ViewerDataHandle    myData ;
  741.     
  742.     if( theWindow == nil)
  743.         return paramErr ;
  744.  
  745.     myData = (ViewerDataHandle)GetWRefCon( theWindow ) ;
  746.     theViewer = (**myData).theViewer ;
  747.     
  748.     DisposeHandle((Handle)myData);
  749.     DisposeWindow(theWindow);
  750.     
  751.     MyAdjustMenus() ;
  752.     return     Q3ViewerDispose(theViewer);
  753. }
  754.  
  755.  
  756. //--------------------------------------------------------------------------------------------
  757. //
  758. //
  759. CGrafPtr MyCreateViewerWindow(  )
  760. {
  761.  
  762.     Rect                theRect ;
  763.     GrafPtr                savedPort ;
  764.     TQ3ViewerObject        myViewerObj ;
  765.     WindowPtr            theWindow ;
  766.     ViewerDataHandle    myData = (ViewerDataHandle)NewHandle(sizeof(ViewerData)) ;
  767.     
  768.     GetPort( &savedPort ) ;
  769.         
  770.     // set the new rect up with a stagger for multiple windows
  771.     SetRect(    &theRect, 
  772.                 gStaggerPos.h, 
  773.                 gStaggerPos.v, 
  774.                 gStaggerPos.h + kWindowWidth, 
  775.                 gStaggerPos.v + kWindowHeight );
  776.  
  777.     gStaggerPos.h += 16 ;
  778.     gStaggerPos.v += 16 ;        // this is not "real staggering code, it don't wrap ;        
  779.                          
  780.     theWindow  = NewCWindow(    nil, 
  781.                                 &theRect, 
  782.                                 "\pUntitled", 
  783.                                 false, 
  784.                                 documentProc, 
  785.                                 (WindowPtr)-1, 
  786.                                 true, 
  787.                                 0L );    
  788.                     
  789.     SetPort( (GrafPtr)theWindow ) ;
  790.     
  791.     // set up the viewer object here
  792.     
  793.     
  794.     myViewerObj = Q3ViewerNew ((CGrafPtr)theWindow,  &theWindow->portRect,  kQ3ViewerDefault) ; 
  795.     
  796.     //stuff the reference to the viewer in the RefCon field of the Window
  797.     (**myData).theViewer = myViewerObj ;
  798.     (**myData).isFileValid = false ;
  799.     SetWRefCon( theWindow, (long)myData );
  800.     
  801.     // make sure it is visible
  802.     ShowWindow( theWindow ) ;
  803.     
  804.     SetPort( savedPort ) ;
  805.     
  806.     return (CGrafPtr)theWindow ;
  807. }
  808.  
  809.  
  810. //-----------------------------------------------------------------------
  811. // returns true if the platform supports appleevents - we won't run
  812. // if it doesn't
  813.  
  814. Boolean SupportsAEVT(void)
  815. {
  816.     OSErr err;
  817.     long response;
  818.         
  819.     err = Gestalt(gestaltAppleEventsAttr,&response);
  820.     if (err!=noErr)
  821.         return false;
  822.         
  823.     return (response && (response << gestaltAppleEventsPresent));
  824. }
  825.  
  826. //-----------------------------------------------------------------------
  827. // called to register our appleevent handlers
  828.  
  829. void RegisterMyEvents(void)
  830. {
  831.     OSErr err;
  832.     
  833.     if (!SupportsAEVT())
  834.         return;
  835.     
  836.     err = AEInstallEventHandler(kCoreEventClass,kAEOpenApplication,NewAEEventHandlerProc(MyAEHandleOAPP),0L,false);
  837.     if (err!=noErr)
  838.         return;
  839.                 
  840.     err = AEInstallEventHandler(kCoreEventClass,kAEOpenDocuments,NewAEEventHandlerProc(MyAEHandleODOC),0L,false);
  841.     if (err!=noErr)
  842.         return;
  843.                 
  844.     err = AEInstallEventHandler(kCoreEventClass,kAEPrintDocuments,NewAEEventHandlerProc(MyAEHandlePDOC),0L,false);
  845.     if (err!=noErr)
  846.         return;
  847.                 
  848.     err = AEInstallEventHandler(kCoreEventClass,kAEQuitApplication,NewAEEventHandlerProc(MyAEHandleQUIT),0L,false);
  849.     if (err!=noErr)
  850.         return;
  851. }
  852.  
  853. //-----------------------------------------------------------------------
  854. // open application event handler for the core event suite, 
  855. // by default we just want a blank new document
  856.  
  857. pascal OSErr MyAEHandleOAPP( AppleEvent *theAppleEvent, AppleEvent *reply, long refCon)
  858. {
  859.     // we don't actually do anything on open - you could,
  860.     // for example you might want to open a blank untitled 
  861.     // window
  862.     
  863.     OSErr err = noErr ;
  864.     return err;
  865. }
  866.  
  867.  
  868. //-----------------------------------------------------------------------
  869. // handler for the open document appleevent handler
  870.  
  871. pascal OSErr MyAEHandleODOC(AppleEvent *theAppleEvent, AppleEvent *reply, long refCon)
  872. {
  873.     FSSpec         myFSS;
  874.     AEDescList    docList;
  875.     OSErr        err,
  876.                 ignoreErr;
  877.     long        index,
  878.                 itemsInList;
  879.     Size         actualSize;
  880.     AEKeyword    keywd;
  881.     DescType    returnedType;
  882.  
  883.     
  884.     err = AEGetParamDesc(theAppleEvent,keyDirectObject,typeAEList,&docList);
  885.     if (err == noErr) {
  886.     
  887.         // see how many descriptor items are in the list
  888.         // this is the number of documents we want to open
  889.         err = AECountItems(&docList,&itemsInList);
  890.  
  891.         // now get each descriptor record from the list
  892.         // coerce the returned data to an FSSpec record, and
  893.         // open the asoociated file
  894.         
  895.         for (index=1; index <= itemsInList && err == noErr; index++) {
  896.         
  897.             err = AEGetNthPtr(    &docList, 
  898.                                 index,
  899.                                 typeFSS,
  900.                                 &keywd,
  901.                                 &returnedType,
  902.                                 (Ptr)&myFSS,
  903.                                 sizeof(myFSS),
  904.                                 &actualSize);
  905.     
  906.             if (err == noErr)    {
  907.             
  908.                 FInfo        fndrInfo ;
  909.                 
  910.                 // we now have a valid FSSpec to reference the file, we need to know 
  911.                 // what type the file is to determine which file open function to call
  912.                 // we can determine this from the finder info for the file
  913.                 
  914.                 err = FSpGetFInfo( &myFSS, &fndrInfo );    
  915.                 
  916.                 // if we got that ok, then we switch on the file  
  917.                 // type (we don't care about the creator type)    
  918.                         
  919.                 if (err == noErr)    {
  920.                 
  921.                     switch( fndrInfo.fdType ) {
  922.                         case 'TEXT':
  923.                         case '3DMF':
  924.                             err =  HandleOpenDoc(&myFSS);
  925.                             break ;
  926.                     }
  927.                 }
  928.             }
  929.         }
  930.         ignoreErr = AEDisposeDesc(&docList);
  931.     }
  932.     return err ;
  933. }
  934.  
  935. //-----------------------------------------------------------------------
  936. // handler for the print document event handler
  937.  
  938. pascal OSErr MyAEHandlePDOC(AppleEvent *theAppleEvent,AppleEvent *reply,long refCon)
  939. {
  940.     FSSpec         myFSS;
  941.     AEDescList    docList;
  942.     OSErr        err;
  943.     long        index,
  944.                 itemsInList;
  945.     Size         actualSize;
  946.     AEKeyword    keywd;
  947.     DescType    returnedType;
  948.  
  949.     
  950.     err = AEGetParamDesc(theAppleEvent,keyDirectObject,typeAEList,&docList);
  951.     if (err == noErr) {
  952.     
  953.         // see how many descriptor items are in the list
  954.         // this is the number of documents we want to open
  955.         err = AECountItems(&docList,&itemsInList);
  956.  
  957.         // now get each descriptor record from the list
  958.         // coerce the returned data to an FSSpec record, and
  959.         // open the asoociated file
  960.         
  961.         for (index=1; index <= itemsInList && err == noErr; index++) {
  962.         
  963.             err = AEGetNthPtr(    &docList, 
  964.                                 index,
  965.                                 typeFSS,
  966.                                 &keywd,
  967.                                 &returnedType,
  968.                                 (Ptr)&myFSS,
  969.                                 sizeof(myFSS),
  970.                                 &actualSize);
  971.     
  972.             if (err == noErr)    {                    
  973.                 // err = HandlePrintDoc( &myFSS );
  974.                 err = errAEEventNotHandled ;         // we don't do this yet...
  975.             }
  976.         }
  977.         err = AEDisposeDesc(&docList);
  978.     }
  979.     return err ;
  980. }
  981.  
  982. //-----------------------------------------------------------------------
  983. // quit appleevent handler
  984.  
  985. pascal OSErr MyAEHandleQUIT(AppleEvent *theAppleEvent,AppleEvent *reply,long refCon)
  986. {
  987.     OSErr             err = noErr ;        // used as return value
  988.     WindowPtr        theWindow ;
  989.     Boolean            quitting = true ;
  990.  
  991.     
  992.     // close all windows and signal to Quit
  993.  
  994.         
  995.     // attempt to close all documents
  996.     while(( theWindow = FrontWindow()) != nil && quitting )
  997.         quitting = (MyDisposeViewerWindow( theWindow ) == noErr);    
  998.         
  999.  
  1000.     // if we closed everything up successfully, we can return noErr, otherwise
  1001.     // indicate to sender of the 'quit' aevt that we canceled
  1002.     
  1003.     if (quitting) {
  1004.         gQuitFlag = true;                    // user didn't cancel
  1005.          AEDisposeDesc(&gSelfAddress);        // Dispose of my self-addressed descriptor.
  1006.     }
  1007.     else {
  1008.         err = userCanceledErr ;
  1009.     }
  1010.             
  1011.     return err ;
  1012. }
  1013.  
  1014.  
  1015. //----------------------------------------------------------------------------------//
  1016. //    Send a Quit Application Apple Event to myself to terminate this app.        
  1017.  
  1018. void MySendQuitApp( void )
  1019. {
  1020.     AppleEvent    myAppleEvent, reply;
  1021.     
  1022.     //    Create the Apple Event.
  1023.     FailIfErr(AECreateAppleEvent( kCoreEventClass, 
  1024.                                   kAEQuitApplication, 
  1025.                                   &gSelfAddress,
  1026.                                   kAutoGenerateReturnID, 
  1027.                                   kAnyTransactionID, 
  1028.                                   &myAppleEvent));
  1029.                                   
  1030.     //    Send the Apple Event.
  1031.       FailIfErr(AESend( &myAppleEvent, 
  1032.                         &reply, 
  1033.                         kAENoReply+kAENeverInteract, 
  1034.                         kAENormalPriority,
  1035.                         kAEDefaultTimeout, 
  1036.                         nil, 
  1037.                         nil));
  1038.                         
  1039.       AEDisposeDesc(&myAppleEvent);                // Dispose of the Apple Event.
  1040. } // MySendQuitApp
  1041.  
  1042.  
  1043. //----------------------------------------------------------------------------------//
  1044. //    Send a Open Document Application Apple Event to myself to open a document.        
  1045.  
  1046. void MySendOpenDoc(FSSpec *myFSSpec)
  1047. {
  1048.      AppleEvent    myAppleEvent;
  1049.     AppleEvent    defReply;
  1050.     AEDescList    docList;
  1051.     OSErr         myErr;
  1052.     OSErr         ignoreErr;
  1053.     
  1054.     myAppleEvent.dataHandle = nil;
  1055.     docList.dataHandle  = nil;
  1056.     defReply.dataHandle = nil;
  1057.         
  1058.     // Create empty list and add one file spec
  1059.     FailIfErr(AECreateList(nil,0,false, &docList));
  1060.     
  1061.     FailIfErr(AEPutPtr(&docList,1,typeFSS,(Ptr)myFSSpec,sizeof(FSSpec)));
  1062.         
  1063.     FailIfErr(AECreateAppleEvent(    kCoreEventClass,
  1064.                                     kAEOpenDocuments,
  1065.                                     &gSelfAddress,
  1066.                                     kAutoGenerateReturnID,
  1067.                                     kAnyTransactionID,
  1068.                                     &myAppleEvent));
  1069.  
  1070.     // Put Params into our event and send it
  1071.  
  1072.     FailIfErr(AEPutParamDesc( &myAppleEvent,
  1073.                               keyDirectObject,
  1074.                               &docList));
  1075.  
  1076.     FailIfErr(AESend( &myAppleEvent,
  1077.                       &defReply,
  1078.                       kAENoReply+kAENeverInteract,
  1079.                       kAENormalPriority,
  1080.                       kAEDefaultTimeout,
  1081.                       nil,
  1082.                       nil));
  1083.         
  1084.         
  1085.     if (myAppleEvent.dataHandle) 
  1086.         ignoreErr = AEDisposeDesc(&myAppleEvent);
  1087.         
  1088.     if (docList.dataHandle) 
  1089.         ignoreErr = AEDisposeDesc(&docList);
  1090.             
  1091. }    // MySendOpenDoc 
  1092.